Log today's location on app open when the day is blank#91
Merged
Conversation
Opening the Where app early in the day could show a blank calendar day because passive tracking (Visits + significant-change) hadn't fired yet. On launch and foreground, take a best-effort one-shot GPS fix and persist it through the normal ingest path when today has no GPS sample. - LocationAuthorizationStatus.allowsForegroundFix (When-In-Use or Always) - LocationIngestor.captureTodayIfNeeded(now:): non-blocking single-flight capture that skips when a GPS sample already exists today (a manual entry doesn't count), persists via the shared ingest path (widget + reminder reconcile + change signal), cancelled on deinit/quiesce - WhereSession.captureTodayIfNeeded(): gated on wantsTracking + a usable authorization; called from start() and appBecameActive() - WhereLaunch: foreground-only capture-today step after reconcile-tracking so a headless background relaunch doesn't fire a foreground fix Co-authored-by: Cursor <cursoragent@cursor.com>
Address a concurrency concern from review: routing the foreground capture through ingest(_:) made it a second writer of the single inFlightIngest slot the stream loop uses, which quiesce() relies on to await an in-flight persist before an erase wipes the store. - Capture now persists via processIngestedSample on its own capturePersistTask handle (single writer, since capture is single-flight), re-checking acceptsSamples synchronously right before registering the handle so quiesce() either skips it or awaits it, never neither. - quiesce() cancels the capture's fix acquisition (best-effort, not awaited so an erase never stalls on a slow ~10s GPS fix) and awaits the capture persist and the stream persist on their independent handles. - Add a single-flight test using a gated location source that holds a fix in flight, proving an overlapping second call is dropped. Co-authored-by: Cursor <cursoragent@cursor.com>
…ground Co-authored-by: Cursor <cursoragent@cursor.com> # Conflicts: # Where/WhereCore/AGENTS.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Opening the Where app early in the day could show a blank calendar day, because location is logged passively (CoreLocation Visits + significant-change) and hadn't fired yet. On launch and foreground, the app now takes a best-effort one-shot GPS fix and persists it when today has no GPS sample, so the current day fills in instead of rendering blank.
Because the fix flows through the normal ingest path, the widget/reminders reconcile and the calendar refreshes reactively via the store
changes()signal — no extra wiring.Behavior
appBecameActive), non-blocking so it never delays UI.Implementation
LocationAuthorizationStatus.allowsForegroundFix— any granted status (When-In-Use or Always).LocationIngestor.captureTodayIfNeeded(now:)— non-blocking, single-flight capture. Skips when a GPS sample already exists today, requests the one-shot fix, and persists it. The persist runs on its owncapturePersistTaskhandle (not the stream loop'sinFlightIngest), andquiesce()awaits it independently so an erase can't wipe the store out from under an in-flight capture — without stalling the erase on a slow (~10s) GPS fix.WhereSession.captureTodayIfNeeded()— applies the gate; called fromstart()andappBecameActive().WhereLaunch— foreground-onlycapture-todaystep afterreconcile-tracking.Testing
LocationAuthorizationTests:allowsForegroundFixtruth table.LocationIngestorTests: captures when today is empty; skips when a GPS sample exists; still captures when only a manual entry exists; skips when no fix; single-flight (overlapping call dropped, via a gated source); existingquiesce*tests still pass.WhereSessionTrackingTests: gating (logs when wanted+authorized; no-ops when tracking off or unauthorized).WhereLaunchTests: step order parity, cold-foreground captures, background launch skips capture.Full
Stuff-iOS-Testsscheme is green and./swiftformat --lintis clean.Made with Cursor